﻿using Autofac;
using FluentValidation;
using Mediator.Infrastructure.AutofacModules;
using MediatR;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Microsoft.Extensions.DependencyInjection
{
    public static partial class MediatorServiceCollectionExtensions
    {
        public static IUnitOfWorkBuilder AddMidatRUnitOfWork(this IServiceCollection serviceCollection, Action<IUnitOfWorkConfig> setting = null)
        {
            if (serviceCollection == null) throw new ArgumentNullException(nameof(serviceCollection));

            var config = new DefaultUnitOfWorkConfig(new ContainerBuilder());


            config.ContainerBuilder.RegisterModule(new MediatorModule());

            setting?.Invoke(config);

            return new DefaultUnitOfWorkBuilder(serviceCollection, config.ContainerBuilder);
        }
        private class DefaultUnitOfWorkConfig : IUnitOfWorkConfig
        {
            public ContainerBuilder ContainerBuilder { get; private set; }
            public DefaultUnitOfWorkConfig(ContainerBuilder containerBuilder) => ContainerBuilder = containerBuilder;

            public void AddNotificationHandler<TNotificationHandler, TNotification>()
                where TNotificationHandler : INotificationHandler<TNotification>
                where TNotification : INotification
            {
                ContainerBuilder.RegisterAssemblyTypes(typeof(TNotificationHandler).GetTypeInfo().Assembly)
                  .AsClosedTypesOf(typeof(INotificationHandler<>));
            }

            public void AddPipelineBehavior<TPipelineBehavior, TRequest, TResponse>() where TPipelineBehavior : IPipelineBehavior<TRequest, TResponse>
            {
                ContainerBuilder.RegisterGeneric(typeof(TPipelineBehavior)).As(typeof(IPipelineBehavior<,>));
            }

            public void AddRequestHandler<TRequest, TResponse>() where TRequest : IRequest<TResponse>
            {
                ContainerBuilder.RegisterAssemblyTypes(typeof(TRequest).GetTypeInfo().Assembly)
                  .AsClosedTypesOf(typeof(IRequestHandler<,>));
            }

            public void AddValidator<TValidator, T>() where TValidator : IValidator<T>
            {
                ContainerBuilder.RegisterAssemblyTypes(typeof(TValidator).GetTypeInfo().Assembly)
                 .Where(t => t.IsClosedTypeOf(typeof(IValidator<>)))
                 .AsImplementedInterfaces();
            }
        }
    }
    public interface IUnitOfWorkBuilder
    {
        IServiceCollection Services { get; }
        ContainerBuilder ContainerBuilder { get; }
        IServiceProvider Build();
    }
    public interface IUnitOfWorkConfig
    {
        void AddRequestHandler<TRequest, TResponse>()
            where TRequest : IRequest<TResponse>;

        void AddNotificationHandler<TNotificationHandler, TNotification>()
            where TNotificationHandler : INotificationHandler<TNotification>
            where TNotification : INotification;

        void AddValidator<TValidator, T>() where TValidator : IValidator<T>;

        void AddPipelineBehavior<TPipelineBehavior, TRequest, TResponse>() where TPipelineBehavior : IPipelineBehavior<TRequest, TResponse>;

    }
}
